1 module hip.api.graphics.text; 2 import hip.api.data.font; 3 public import hip.math.rect : Size; 4 5 /** 6 * All the combinations that exists for align, specifies firstly the vertical position, then the horizontal: 7 * i.e: centerLeft is center vertical, left horizontally 8 */ 9 enum HipTextAlign : ubyte 10 { 11 ///This means leftCenter internally 12 defaultAlign = 0, 13 centerH = 0b000001, 14 left = 0b000010, 15 right = 0b000100, 16 centerV = 0b001000, 17 top = 0b010000, 18 bottom = 0b100000, 19 20 21 topCenter = top | centerH, 22 topLeft = top | left, 23 topRight = top | right, 24 25 center = centerV | centerH, 26 centerLeft = centerV | left, 27 centerRight= centerV | right, 28 29 botCenter = bottom | centerH, 30 botLeft = bottom | left, 31 botRight = bottom | right, 32 33 horizontalMask = centerH | left | right, 34 verticalMask = centerV | top | bottom, 35 } 36 37 HipTextAlign getAlignH(HipTextAlign input) 38 { 39 return cast(HipTextAlign)(input & HipTextAlign.horizontalMask); 40 } 41 42 HipTextAlign getAlignV(HipTextAlign input) 43 { 44 return cast(HipTextAlign)(input & HipTextAlign.verticalMask); 45 } 46 47 /** 48 * 49 * Params: 50 * x = Specified X 51 * y = Specified Y 52 * width = The width of the subject 53 * height = The height of the subject 54 * alignment = Alignment for calculating newX and newY 55 * newX = Out arg 56 * newY = Out arg 57 * bounds = The bounds to align to. If It is == 0, it won't be considered in the calculation 58 */ 59 void getPositionFromAlignment( 60 int x, int y, int width, int height, HipTextAlign alignment, 61 out int newX, out int newY, Size bounds 62 ) 63 { 64 with(HipTextAlign) 65 { 66 switch(getAlignH(alignment)) 67 { 68 case centerH: 69 if(bounds.width != 0) 70 newX = (x + (bounds.width)/2) - (width / 2); 71 else 72 newX = x - width/2; 73 break; 74 case right: 75 if(bounds.width != 0) 76 newX = x + bounds.width - width; 77 else 78 newX = x - width; 79 break; 80 case left: 81 newX = x; 82 break; 83 default: assert(false, "Some invalid horizontal alignment was received."); 84 } 85 switch(getAlignV(alignment)) 86 { 87 case centerV: 88 if(bounds.height != 0) 89 newY = y + (bounds.height/2) - height/2; 90 else 91 newY = y- height/2; 92 break; 93 case bottom: 94 if(bounds.height != 0) 95 newY = y + bounds.height - height; 96 else 97 newY = y - height; 98 break; 99 case top: 100 newY = y; 101 break; 102 default: assert(false, "Some invalid vertical alignment was received."); 103 } 104 } 105 } 106 107 /** 108 * 109 * Params: 110 * font = The font used as a reference to build the quad 111 * vertices = Output vertices 112 * text = The text to build the vertices 113 * x = Start X 114 * y = Start Y 115 * depth = Depth for possibly Z buffer 116 * scale = Rescaling the font 117 * align_ = Alignment on where it will show 118 * bounds = -1 value will make it be ignored. If exists, it will be used both for word wrap and for alignment to the size specified 119 * wordWrap = If the text will line-break if it reaches the size too big 120 * shouldRenderSpace = Render ' ' characters or not. 121 * Returns: 122 */ 123 int putTextVertices( 124 IHipFont font, HipTextRendererVertexAPI[] vertices, 125 string text, 126 int x, int y, float depth, float scale = 1.0f, 127 HipTextAlign align_ = HipTextAlign.center, 128 Size bounds = Size.init, 129 bool wordWrap = false, 130 bool shouldRenderSpace 131 ) 132 { 133 int yoffset = 0; 134 bool isFirstLine = true; 135 int vI = 0; 136 int height = cast(int)(font.getTextHeight(text) * scale); 137 138 foreach(HipLineInfo lineInfo; font.wordWrapRange(text, wordWrap ? bounds.width : -1)) 139 { 140 if(!isFirstLine) 141 { 142 yoffset+= font.lineBreakHeight * scale; 143 } 144 isFirstLine = false; 145 int xoffset = 0; 146 int displayX = void, displayY = void; 147 int lineYOffset = 0; 148 // if(align_ & HipTextAlign.top) lineYOffset = yoffset - cast(int)(lineInfo.minYOffset * scale); 149 lineYOffset = -cast(int)(lineInfo.minYOffset * scale); 150 151 getPositionFromAlignment( 152 x, y, 153 cast(int)(lineInfo.width * scale), cast(int)(height ? height : lineInfo.height * scale), 154 align_, 155 displayX, displayY, 156 bounds 157 ); 158 for(int i = 0; i < lineInfo.line.length; i++) 159 { 160 int kerning = lineInfo.kerningCache[i]; 161 const(HipFontChar)* ch = lineInfo.fontCharCache[i]; 162 163 switch(lineInfo.line[i]) 164 { 165 case ' ': 166 if(!shouldRenderSpace) 167 { 168 xoffset+= font.spaceWidth * scale; 169 break; 170 } 171 goto default; 172 default: 173 if(ch is null) continue; 174 ch.putCharacterQuad( 175 cast(float)(xoffset+displayX+(ch.xoffset+kerning) *scale), 176 cast(float)(yoffset+displayY+lineYOffset + ch.yoffset*scale), depth, 177 vertices[vI..vI+4], scale 178 ); 179 vI+= 4; 180 xoffset+= ch.xadvance*scale; 181 } 182 } 183 } 184 return vI; 185 }